#ifndef _GEO_GEOBASE_H_
#define _GEO_GEOBASE_H_

#include "../stdafx.h"

//	marco definition
#define SKE_ERROR_THRESHOLD	1e-3
#define SKE_INF_POINT		500
#define SKE_ERROR_POINT		15
#define SKE_MIN_STROKE_LENGTH	10


//	point
struct CVertex3D;

typedef CVertex3D CVector3D;

struct CVertex3D
{
	double m_data[3];

	CVertex3D operator+(const CVertex3D& p);
	const CVector3D operator-(const CVertex3D& p);
	CVertex3D operator*(const double d);
	CVertex3D operator/(const double d);
	const bool operator==(const CVertex3D& p);
	const bool operator!=(const CVertex3D& p);
	const double operator*(const CVertex3D& p);

	void SetValue(double d0, double d1, double d2);
	void Clip();
	void Normalize();
	double CalcLength();
};

struct CVertex2D;

typedef CVertex2D CVector2D;

struct CVertex2D
{
	double m_data[2];

	const bool operator==(const CVertex2D& p);
	const double operator*(const CVertex2D& p);
	const CVector2D operator-(const CVertex2D& p);

	void SetValue(double d0, double d1);
	void Clip();
	void Normalize();
	double CalcLength();
};

//	vertex
struct CVertex
{
	CVertex2D m_v2D;
	CVertex3D m_v3D;

	const bool operator==(const CVertex& v);
	void Clip();
};

//	scaffold

struct CScaffold
{
	CVertex* m_start;
	CVertex* m_end;

	const bool operator==(const CScaffold&s);
};

//	line segment

typedef CScaffold CLineSegment;

//	curve
struct CCurve
{
	CVertex* m_start;
	CVertex* m_mid;
	CVertex* m_end;

	const bool operator==(const CCurve curve);
	const bool operator!=(const CCurve curve);
};

//	surface
struct CSurface
{
	vector<CVertex3D> m_vertices;
	CVector3D m_normal;
};

//	algebra

enum SKE_LINEINTERSECT_SOLUTION	{NO_SOL, ONE_SOL, INF_SOL};

CVertex3D ComputeIntersection(
	CVertex3D p1, 
	CVertex3D p2, 
	CVector3D v1, 
	CVector3D v2,
	SKE_LINEINTERSECT_SOLUTION& type);

CVertex2D ComputeIntersection(
	CVertex2D p1,
	CVertex2D p2,
	CVector2D v1,
	CVector2D v2,
	SKE_LINEINTERSECT_SOLUTION& type
	);

double CalcDistance(CVertex2D p1, CVertex2D p2);
double CalcDistance(CVertex3D p1, CVertex3D p2);

bool IsParallel(CVector2D v1, CVector2D v2);
bool IsParallel(CVector3D v1, CVector3D v2);

CVertex2D Lerp(CVertex2D p1, CVertex2D p2, double ratio);
double Lerp(double x1, double y1, double x2, double y2, double x0);

CVector3D Cross(CVector3D v1, CVector3D v2);

float CalcAngle(CVector2D v1, CVector2D v2);
float CalcAngle(CVector3D v1, CVector3D v2);

//	projection
// http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix

bool InverseMatrix(double m[16], double invOut[16]);

bool IsInLineSegment(CVertex2D p2D, CLineSegment l);
bool IsInLineSegment(CVertex3D p3D, CLineSegment l);

bool IsInScaffold(CVertex2D p2D, CScaffold s);
bool IsInScaffold(CVertex3D p3D, CScaffold s);

//	typedef
typedef vector<CVertex2D>::iterator CVertex2DIter;


#endif